/*-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License.You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
	
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
	
The Original Code is Fever RS ( ActionScript 3 ) Framework code.
	
The Initial Developer of the Original Code is Romain Ecarnot.
Portions created by Initial Developer are Copyright (C) 2006
the Initial Developer. All Rights Reserved.
	
Contributor(s):
	
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-----------------------------------------------------------------------------*/

package fever.utils 
{

	/**
	 * Mathematics methods.
	 * 
	 * @author Romain Ecarnot
	 */
	final public class MathUtil 
	{
		//--------------------------------------------------------------------
		// Public API
		//--------------------------------------------------------------------		
		
		/**
		 * Converts passed-in <code>angle</code> angle in radian.
		 * 
		 * @param angle Angle in degree 
		 * @return Radian convertion
		 */ 
		public static function toRadian( angle : Number ) : Number
		{
			return ( angle * Math.PI ) / 180;
		}

		/**
		 * Converts passed-in <code>angle</code> angle in degree.
		 * 
		 * @param angle Angle in radian
		 * @return Radian convertion
		 */ 
		public static function toDegre( angle : Number ) : Number
		{
			return ( angle * 180 ) / Math.PI;
		}

		/**
		 * Round passed <code>value</code> with passed-in 
		 * <code>digits</code> precision.
		 * 
		 * @param value Value to round
		 * @param digits Round precision 
		 */
		public static function round( value : Number, digits : Number ) 
			: Number
		{
			return Math.round( 
				value * Math.pow( 10, digits ) 
			) / Math.pow( 10, digits );
		}

		/**
		 * Returns random number between <code>v1</code> and <code>v2</code> 
		 * value.
		 * 
		 * <p>Arguments are automaticcaly re-order.</p>
		 * 
		 * @param v1 First interval limit
		 * @param v2 Second interval limit 
		 * @param rounded Indicates if result must be round or not
		 */
		public static function random( v1 : Number, v2 : Number, 
			rounded : Boolean = false ) : Number
		{ 
			var nMax : Number = Math.max( v1, v2 );
			var nMin : Number = Math.min( v1, v2 );
			var r : Number = ( Math.random( ) * ( nMax - nMin ) + nMin );
			
			return ( rounded ) ? Math.round( r ) : r;
		}

		/**
		 * Returns square value of passed-in <code>value</code> value.
		 * 
		 * @param value Number 
		 */
		public static function square( value : Number ) : Number
		{
			return ( value * value );
		}

		/**
		 * Returns inverse of passed-in <code>value</code> value
		 * 
		 * @param value Number 
		 */
		public static function inverse( value : Number ) : Number
		{
			var n : Number = value >> 0;
			return (!n) ? 0 : ( 1 / n );
		}

		/**
		 * Returns sum of elements passed in <code>array</code> collection.
		 * 
		 * @param array Values array
		 */
		public static function sum( array : Array ) : Number
		{
			var l : Number = array.length;
			var r : Number = 0;
			
			if(!l) return 0;
			
			while(--l > -1)	r += array[l];
			
			return r;
		}

		/**
		 * Returns mean of elements passed in <code>array</code> collection.
		 * 
		 * @param a Values array 
		 */
		public static function mean( a : Array ) : Number
		{
			var nL : Number = a.length;
			var l : Number = nL;
			var r : Number = 0;
			
			if(!l) return 0;
			
			while(--l > -1) r += a[l];
			
			return ( r / nL );
		}

		/**
		 * Returns the factorial of <code>n</code>
		 * 
		 * @param n Number
		 */
		public static function factorial( n : Number) : Number
		{
			if ( n != 0 ) return n * factorial( n - 1 );
	        else return 1;
		}

		/**
		 * Returns percent value from passed-in <code>value</code> according 
		 * <code>total</code> one.
		 * 
		 * <p>If result is not a number or is is infinite, 
		 * returns <code>null</code>.</p>
		 * 
		 * @param value Number to check
		 * @param total Reference number.
		 * @param rounded <code>true</code> to round the percent result
		 * 
		 * @return Percent value or <code>null</code>
		 */
		public static function percent( value : Number, total : Number, 
			rounded : Boolean ) : Number
		{
			var n : Number = ( value / total ) * 100;
			return ( isNaN( n ) || !isFinite( n ) ) ? 0 : ( rounded ) 
				? Math.round( n ) 
				: n ;
		}

		/**
		 * Calculates and returns the variance of elements in 
		 * passed-in <code>array</code> collection.
		 * 
		 * @param a Array with elements to check
		 */
		public static function getVariance( a : Array ) : Number
		{
			var l : int = a.length;
			var sum : Number = 0;
			var sqr : Number = 0;
			
			for( var i : int = 0; i < l ; i++ )
			{
				var n : Number = a[i];
				sum += n;
				sqr += ( n * n );
			}
	     
			var mean : Number = sum / l;
			return ( sqr / l ) - ( mean * mean );
		}

		/**
		 * Calculates and returns standart deviation of elements in 
		 * passed-in <code>array</code> collection.
		 * 
		 * @param a Array with elements to check
		 */
		public static function getStandartDeviation( a : Array ) : Number
		{
			return Math.sqrt( getVariance( a ) );
		}
		
		/**
		 * Returns <code>true</code> if the passed-in 
		 * integer <code>n</code> is odd.
		 * 
		 * @param n the integer to check
		 * @return <code>true</code> if <code>n</code> is 
		 * odd else <code>false</code>
		 */
		public static function isOdd( n : int ) : Boolean
		{
			return Boolean( n % 2 );
		}
		
		/**
		 * Returns <code>true</code> if the passed-in 
		 * integer <code>n</code> is even.
		 * 
		 * @param n the integer to check
		 * @return <code>true</code> if <code>n</code> is 
		 * even else <code>false</code>
		 */
		public static function isEven( n : int ) : Boolean
		{
			return ( n % 2 == 0 );
		}
		
		/**
		 * Returns <code>true</code> if passed-in number 
		 * <code>n</code> is a prime.
		 * 
		 * <p>A prime number is a positive integer that has no positive 
		 * integer divisors other than 1 and itself.</p>
		 * 
		 * @param n the number to check
		 * @return <code>true</code> if <code>n</code> is a 
		 * prime, else <code>false</code>
		 */	
		public static function isPrime( n : int ) : Boolean
		{
			if (n == 1) return false;
			if (n == 2) return true;
			if (n % 2 == 0) return false;
			
			for ( var i : Number = 3, e : Number = Math.sqrt( n ); i <= e; i += 2 )
			{
				if ( n % i == 0 ) return false;
			}
			return true;
		}
		
		
		//--------------------------------------------------------------------
		// Private implementations
		//--------------------------------------------------------------------
		
		/** @private */
		public function MathUtil( acess : PrivateConstructorAccess ) 
		{
		}
	}
}


internal class PrivateConstructorAccess 
{
}